home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / security / smrsh / smrsh.c.Z / smrsh.c
Encoding:
C/C++ Source or Header  |  1993-11-04  |  4.1 KB  |  192 lines

  1. /*
  2. **  SMRSH -- sendmail restricted shell
  3. **
  4. **    This is a patch to get around the prog mailer bugs in most
  5. **    versions of sendmail.
  6. **
  7. **    Use this in place of /bin/sh in the "prog" mailer definition
  8. **    in your sendmail.cf file.  You then create CMDDIR (owned by
  9. **    root, mode 755) and put links to any programs you want
  10. **    available to prog mailers in that directory.  This should
  11. **    include things like "vacation" and "procmail", but not "sed"
  12. **    or "sh".
  13. **
  14. **    Leading pathnames are stripped from program names so that
  15. **    existing .forward files that reference things like
  16. **    "/usr/ucb/vacation" will continue to work.
  17. **
  18. **    The following characters are completely illegal:
  19. **        <  >  |  ^  ;  &  $  `  (  ) \n \r
  20. **    This is more restrictive than strictly necessary.
  21. **
  22. **    To use this, edit /etc/sendmail.cf, search for ^Mprog, and
  23. **    change P=/bin/sh to P=/usr/etc/smrsh, where this compiled
  24. **    binary is installed /usr/etc/smrsh.
  25. **
  26. **    In loving memory of RTM.  11/02/93.
  27. */
  28.  
  29. #include <stdio.h>
  30. #include <sys/file.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33. #include <sysexits.h>
  34. #include <syslog.h>
  35.  
  36. /* directory in which all commands must reside */
  37. #ifndef CMDDIR
  38. # define CMDDIR        "/usr/adm/sm.bin"
  39. #endif
  40.  
  41. /* characters disallowed in the shell "-c" argument */
  42. #define SPECIALS    "<|>^();&`$\r\n"
  43.  
  44. /* default search path */
  45. #ifndef PATH
  46. # define PATH        "/bin:/usr/bin:/usr/ucb"
  47. #endif
  48.  
  49. char    Version[] =    "SMRSH 1.2";
  50.  
  51. main(argc, argv)
  52.     int argc;
  53.     char **argv;
  54. {
  55.     register char *p;
  56.     register char *q;
  57.     register char *cmd;
  58.     int i;
  59.     char *newenv[2];
  60.     char cmdbuf[1000];
  61.     char pathbuf[1000];
  62.  
  63. #ifdef ultrix
  64.     openlog("smrsh", 0);
  65. #else
  66.     openlog("smrsh", LOG_ODELAY|LOG_CONS, LOG_MAIL);
  67. #endif
  68.  
  69.     strcpy(pathbuf, "PATH=");
  70.     strcat(pathbuf, PATH);
  71.     newenv[0] = pathbuf;
  72.     newenv[1] = NULL;
  73.  
  74.     /*
  75.     **  Do basic argv usage checking
  76.     */
  77.  
  78.     if (argc != 3 || strcmp(argv[1], "-c") != 0)
  79.     {
  80.         fprintf(stderr, "Usage: %s -c command\n", argv[0]);
  81.         syslog(LOG_ERR, "usage");
  82.         exit(EX_USAGE);
  83.     }
  84.  
  85.     /*
  86.     **  Disallow special shell syntax.  This is overly restrictive,
  87.     **  but it should shut down all attacks.
  88.     **  Be sure to include 8-bit versions, since many shells strip
  89.     **  the address to 7 bits before checking.
  90.     */
  91.  
  92.     strcpy(cmdbuf, SPECIALS);
  93.     for (p = cmdbuf; *p != '\0'; p++)
  94.         *p |= '\200';
  95.     strcat(cmdbuf, SPECIALS);
  96.     p = strpbrk(argv[2], cmdbuf);
  97.     if (p != NULL)
  98.     {
  99.         fprintf(stderr, "%s: cannot use %c in command\n",
  100.             argv[0], *p);
  101.         syslog(LOG_CRIT, "uid %d: attempt to use %c in command: %s",
  102.             getuid(), *p, argv[2]);
  103.         exit(EX_UNAVAILABLE);
  104.     }
  105.  
  106.     /*
  107.     **  Do a quick sanity check on command line length.
  108.     */
  109.  
  110.     i = strlen(argv[2]);
  111.     if (i > (sizeof cmdbuf - sizeof CMDDIR - 2))
  112.     {
  113.         fprintf(stderr, "%s: command too long: %s\n", argv[0], argv[2]);
  114.         syslog(LOG_WARNING, "command too long: %.40s", argv[2]);
  115.         exit(EX_UNAVAILABLE);
  116.     }
  117.  
  118.     /*
  119.     **  Strip off a leading pathname on the command name.  For
  120.     **  example, change /usr/ucb/vacation to vacation.
  121.     */
  122.  
  123.     /* strip leading spaces */
  124.     for (q = argv[2]; *q != '\0' && isascii(*q) && isspace(*q); )
  125.         q++;
  126.  
  127.     /* find the end of the command name */
  128.     p = strpbrk(q, " \t");
  129.     if (p == NULL)
  130.         cmd = &q[strlen(q)];
  131.     else
  132.     {
  133.         *p = '\0';
  134.         cmd = p;
  135.     }
  136.  
  137.     /* search backwards for last / (allow for 0200 bit) */
  138.     while (cmd > q)
  139.     {
  140.         if ((*--cmd & 0177) == '/')
  141.         {
  142.             cmd++;
  143.             break;
  144.         }
  145.     }
  146.  
  147.     /* cmd now points at final component of path name */
  148.  
  149.     /*
  150.     **  Check to see if the command name is legal.
  151.     */
  152.  
  153.     (void) strcpy(cmdbuf, CMDDIR);
  154.     (void) strcat(cmdbuf, "/");
  155.     (void) strcat(cmdbuf, cmd);
  156. #ifdef DEBUG
  157.     printf("Trying %s\n", cmdbuf);
  158. #endif
  159.     if (access(cmdbuf, X_OK) < 0)
  160.     {
  161.         /* oops....  crack attack possiblity */
  162.         fprintf(stderr, "%s: %s not available for sendmail programs\n",
  163.             argv[0], cmd);
  164.         if (p != NULL)
  165.             *p = ' ';
  166.         syslog(LOG_CRIT, "uid %d: attempt to use %s", getuid(), cmd);
  167.         exit(EX_UNAVAILABLE);
  168.     }
  169.     if (p != NULL)
  170.         *p = ' ';
  171.  
  172.     /*
  173.     **  Create the actual shell input.
  174.     */
  175.  
  176.     strcpy(cmdbuf, CMDDIR);
  177.     strcat(cmdbuf, "/");
  178.     strcat(cmdbuf, cmd);
  179.  
  180.     /*
  181.     **  Now invoke the shell
  182.     */
  183.  
  184. #ifdef DEBUG
  185.     printf("%s\n", cmdbuf);
  186. #endif
  187.     execle("/bin/sh", "/bin/sh", "-c", cmdbuf, NULL, newenv);
  188.     syslog(LOG_CRIT, "Cannot exec /bin/sh: %m");
  189.     perror("/bin/sh");
  190.     exit(EX_OSFILE);
  191. }
  192.